package View;

import Audio.AudioCapture;
import Network.ClientTCP;
import Network.ThreadServerUDP;
import chataudio.Constant;
import controleur.AbstractChatControleur;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import model.Connection;
import model.User;
import observer.ActivityObserver;
import observer.ListObserver;
import observer.UserObserver;



/**
 * La classe MainFrame sert à la génération de la fenêtre principal<br>
 * @author Romain Bustos
 * @author Matthieu Perrin
 * @version 1.0
 */
public class MainFrame implements ListObserver, UserObserver, ActivityObserver {
    //********************************************************
    //********************** ICONS ***************************
    //********************************************************
    final private String pathicon = "/Icon/";
    final private ImageIcon iconExit = new ImageIcon(getClass().getResource(pathicon + "exit.png"));
    final private ImageIcon iconNew = new ImageIcon(getClass().getResource(pathicon + "Connect.png"));
    final private ImageIcon iconUser = new ImageIcon(getClass().getResource(pathicon + "User-Edit.png"));
    final private ImageIcon iconTool = new ImageIcon(getClass().getResource(pathicon + "Toolbox.png"));
    final private ImageIcon iconSrvUDP = new ImageIcon(getClass().getResource(pathicon + "Server-Go.png"));
    final private ImageIcon iconReqUDP = new ImageIcon(getClass().getResource(pathicon + "Telephone-Go.png"));
    final private ImageIcon iconDialAdd = new ImageIcon(getClass().getResource(pathicon + "Comment-Add22.png"));
    final private ImageIcon iconStatusSEND = new ImageIcon(getClass().getResource(pathicon + "User-Go.png"));
    final private ImageIcon iconStatusWAIT = new ImageIcon(getClass().getResource(pathicon + "User-Orange.png"));
    final private ImageIcon iconStatusREFUSED = new ImageIcon(getClass().getResource(pathicon + "User-Red.png"));
    final private ImageIcon iconStatusACCEPTED = new ImageIcon(getClass().getResource(pathicon + "User-Green.png"));
    final private ImageIcon iconGreen = new ImageIcon(getClass().getResource(pathicon + "Bullet-Green.png"));
    final private ImageIcon iconRed = new ImageIcon(getClass().getResource(pathicon + "Bullet-Red.png"));
    final private ImageIcon iconMute = new ImageIcon(getClass().getResource(pathicon + "Sound-Mute.png"));
    
    int h = 0;
    int m = 0;
    int s = 0;
    boolean running = false;
    protected JFrame frame = new JFrame();
    private JPanel itemPanel = new JPanel();
    private JTabbedPane tabPane = new JTabbedPane();
    private JSplitPane splitPane;
    private JPanel mainPanel = new JPanel();
    private Dimension size = new Dimension(800, 600);
    private AbstractChatControleur control;
    private JTextField textField;
    private JList listattente;
    private JScrollPane scrollPanel;
    private JLabel UserConected;
    private JPanel ledActivity = new JPanel();
    private JLabel labelChrono = new JLabel();
    
    
    /**
    *<b>Constructeur de la classe MainFrame</b><br> 
    * @param controleur 
    */
    public MainFrame(AbstractChatControleur controleur){
        modificationFermetureCroix();
        buildFrame(controleur);
    }
    
    /**
    *<b>Methode buildFrame</b><br>
    * construit la fenêtre principal<br>
    * @param controleur 
    */
    private void buildFrame(AbstractChatControleur controleur){
        this.control = controleur;
        frame.setTitle("Chat Audio");
        frame.setJMenuBar(buildMenu());
        frame.add(buildPanel());
        frame.setPreferredSize(size);
        frame.setSize(800, 600);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	frame.setContentPane(mainPanel);
        frame.pack();
        frame.validate();
    }
    
    /**
    *<b>Methode displayFrame</b><br>
    * Permet de rendre la fenêtre principal visible<br> 
    */
    public void displayFrame(){
        frame.setVisible(true);
    }
    
    /**
    *<b>Methode buildMenu</b><br>
    * construit un menu
    * @return JMenuBar
    */
    private JMenuBar buildMenu(){
                  
        JMenuBar menu = new JMenuBar();
        
        //----------------------------
        //-------- Menu Fichier-------
        //----------------------------
        
        JMenu menuFile = new JMenu("Fichier");
        
        //Option <Quitter>
        JMenuItem itemQuit = new JMenuItem("Quitter", iconExit);
        itemQuit.setName("btnQuit");
        itemQuit.addActionListener(new MenuListener());
        
        
        //Option <Nouvelle Connection>
        JMenuItem itemNew = new JMenuItem("Nouvelle Connection", iconNew);
        itemNew.setName("btnCon");
        itemNew.addActionListener(new MenuListener());
        
        
        //Ajout dans le menu
        menuFile.add(itemNew);
        menuFile.add(itemQuit);
        
        //---------------------------
        //----- Fin Menu Fichier ----
        //---------------------------
        
        //----------------------------
        //----- Menu Paramètres ------
        //----------------------------
        JMenu menuSetting = new JMenu("Paramètres");
        
        //----- Option <Gestion des utilisateurs> -----
        JMenuItem itemUser = new JMenuItem("Gestion des utilisateurs", iconUser);
        itemUser.setName("btnUser");
        itemUser.addActionListener(new MenuListener());
        
        
        //------ Option <Préférences> ---- 
        JMenuItem itemPreference = new JMenuItem("Préférences", iconTool);
        itemPreference.setName("btnPref");
        itemPreference.addActionListener(new MenuListener());
        
        
        
        //Ajout dans menuSetting
        menuSetting.add(itemUser);
        menuSetting.add(itemPreference);
        //----------------------------
        //----- Fin Menu Paramètres --
        //----------------------------
        
        
        //----------------------------
        //----- Menu Debug -----------
        //----------------------------
        JMenu menuDebug = new JMenu("Debug");
        
        //----- Option <Lancer une écoute sur UDP> -----
        JMenuItem itemSrvUDP = new JMenuItem("Lancer une écoute sur UDP", iconSrvUDP);
        itemSrvUDP.setName("btnSrvUDP");
        itemSrvUDP.addActionListener(new MenuListener());
        
        
        //------ Option <Lancer un appel UDP> ---- 
        JMenuItem itemReqUDP = new JMenuItem("Lancer un appel UDP", iconReqUDP);
        itemReqUDP.setName("btnReqUDP");
        itemReqUDP.addActionListener(new MenuListener());
        
        //------ Option <EasterEgg> ---- 
        JMenuItem itemBug = new JMenuItem("Signaler un bug...", iconReqUDP);
        itemBug.setName("btnBug");
        itemBug.addActionListener(new MenuListener());
        
        //Ajout dans menuDebug
        menuDebug.add(itemSrvUDP);
        menuDebug.add(itemReqUDP);
        menuDebug.add(itemBug);
        
        //----------------------------
        //----- Fin Menu Debug -----------
        //----------------------------
        
        //Ajout des menu dans la menuBar
        menu.add(menuFile);
        menu.add(menuSetting);
        if ( Constant.debug ) menu.add(menuDebug);
        
        return menu;
    }
    
    /**
    *<b>Methode buildConnectionBar</b>
    * Consruit un Panel qui offre la posibilité de lancer une nouvelle connexion<br>
    * @return JPanel
    */
    private JPanel buildConnectionBar(){
    
        //Construction de la ToolBar
        JPanel connectionBarbar = new JPanel(new BorderLayout());
        
        //Construction du Panel <Nouvelle Connection>
        JPanel newCon = new JPanel();
        newCon.setBorder(BorderFactory.createTitledBorder("Nouvelle Connection"));
        
        textField = new JTextField();
        
        textField.setPreferredSize(new Dimension(100, 20));
        textField.setMaximumSize(new Dimension(100, 20));
        
        textField.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent key) {
                if (key.getKeyCode() == KeyEvent.VK_ENTER) {
                    try {
                        control.createConnection(textField.getText());
                    } catch (UnknownHostException ex) {
                        Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        });
        
        //Construction du Boutton
        JButton bAdd = new JButton("OK");
        bAdd.setBounds(0, 0, 16, 16);
        bAdd.setBorder(new EmptyBorder(3,3,3,3));
        bAdd.setName("addbtn");
        bAdd.setMaximumSize(new Dimension(40, 20));
        bAdd.addActionListener(new ConnectionPanelListener());
        
        //Ajout au Conteneur
        newCon.add(textField);
        newCon.add(bAdd);
        connectionBarbar.add(newCon, BorderLayout.WEST);
       
        //Construction du Boutton Autodiscover
        JButton bauto = new JButton("AutoDiscover");
        bauto.setBounds(0, 0, 16, 16);
        bauto.setBorder(new EmptyBorder(3,3,3,3));
        bauto.setName("auto");
        bauto.setMaximumSize(new Dimension(80, 20));
        bauto.addActionListener(new ConnectionPanelListener());
       
        newCon.add(bauto);
        
        UserConected = new JLabel();
        setUserTextConnected();
        
        newCon.setPreferredSize(new Dimension(300, 50));
        
        connectionBarbar.add(UserConected, BorderLayout.CENTER);
        connectionBarbar.add(ledActivity, BorderLayout.EAST);
        
        return connectionBarbar;
    }
    
    /**
    *<b>Methode buildPanel</b>
    * Consruit un Panel qui affiche les listes<br>
    * @return JPanel
    */
    private JPanel buildPanel(){
        Dimension scrollSize = new Dimension (300, 140);
        Dimension minimumSize = new Dimension(200, 50);

        mainPanel.setLayout(new BorderLayout());
        
        itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));
        itemPanel.setBorder(BorderFactory.createTitledBorder("Connexions en attente"));
        scrollPanel = new JScrollPane(itemPanel);
        scrollPanel.setPreferredSize(scrollSize);
        
        //----TabPan
        tabPane.setPreferredSize(scrollSize);
        tabPane.setBorder(BorderFactory.createTitledBorder("Connexion en cours"));
        
        
        //Create a split pane with the two scroll panes in it.
        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,scrollPanel, tabPane);
        splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
        splitPane.setDividerLocation(400);

        //Provide minimum sizes for the two components in the split pane
        
        scrollPanel.setMinimumSize(minimumSize);
        tabPane.setMinimumSize(minimumSize);
        
        mainPanel.add(buildConnectionBar(), BorderLayout.NORTH);
        mainPanel.add(splitPane, BorderLayout.CENTER);
        
        return mainPanel;
    }
    
    /**
    *<b>Methode buildItem</b>
    * Consruit les items de la liste d'attente<br>
    * @param connection 
    */
    public void buildItem(Connection connection){
        Dimension itemSize = new Dimension(400, 40);
        JPanel item = new JPanel(new BorderLayout());
        
        item.setMaximumSize(itemSize);
        item.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
        JLabel user = new JLabel(connection.getUser() + "@" + connection.getAdresse());
        
        //Chaque état de l'objet connexion correspond un affichage
                
        item.add(createIconLabel(connection.getState()), BorderLayout.WEST);
        if ( Constant.debug ) item.add(new JLabel(connection.getState().toString()), BorderLayout.SOUTH);        
        item.add(createButtonPanel(connection), BorderLayout.EAST);
        item.add(user, BorderLayout.CENTER);
        
        
        itemPanel.add(item);
        //frame.pack();
        //frame.validate();
    }
    
    
    
    private JLabel createIconLabel(Constant.Status etat)
    {
        switch ( etat )
        {
            case SEND :
                return new JLabel(iconStatusSEND);
                
            case WAITING_FOR_ACCEPTATION :
            case WAITING_FOR_RESPONSE :
                return new JLabel(iconStatusWAIT);
                
            default:
                return new JLabel(iconStatusREFUSED);
        }
    }
    
    
    
    private JPanel createButtonPanel(Connection connection)
    {
        JPanel btnPanel = new JPanel();
        
        JButton btnAccept = new JButton("Accepter");
        JButton btnRefuse = new JButton("Refuser");
        JButton btnAnnul = new JButton("Annuler");
        btnAccept.setName("btnAccept");
        btnRefuse.setName("btnRefuse");
        btnAnnul.setName("btnAnnul");
        btnAccept.addActionListener(new WaitPanelListener(connection));
        btnRefuse.addActionListener(new WaitPanelListener(connection));
        btnAnnul.addActionListener(new WaitPanelListener(connection));
        
        switch ( connection.getState() )
        {
            case SEND :
                
                btnPanel.add(new JButton("Annuler"), BorderLayout.EAST);
                break;
                
            case WAITING_FOR_ACCEPTATION :              
                btnPanel.add(btnAccept);
                btnPanel.add(btnRefuse);
                break;
                
            case WAITING_FOR_RESPONSE :       
                btnPanel.add(btnAnnul);
                break;
                
            case STOP :          
                btnPanel.add(btnAccept);
                btnPanel.add(btnRefuse);
                break;
                    
                
            default:
                btnPanel.add(btnAnnul);
                
        }
        return btnPanel;
    }
    
    
    
    /**
    *<b>Methode buildTab</b>
    * Consruit la liste active<br>
    * @param connection 
    */
    private void buildTab(Connection connection){
        JComponent contentTab = buildTabItem(connection);
        tabPane.addTab(connection.getUser(), contentTab);
    }
    
    /**
    *<b>Methode buildTabItem</b>
    * Consruit les Items de la liste active<br>
    * @param connection 
    */
    private JComponent buildTabItem(Connection conn) {
        JButton btnStop = new JButton("Stop");
        btnStop.setName("stop");
        btnStop.addActionListener(new tabPanelListener(conn));
        JPanel mainTabPanel = new JPanel(new BorderLayout());
        JPanel infoPanel = new JPanel(new GridLayout(3,1));
        JPanel playerPanel = new JPanel();
        JButton mute = new JButton(iconMute);
        mute.setName("mute");
        mute.addActionListener(new tabPanelListener(conn));
        
        playerPanel.setBorder(BorderFactory.createTitledBorder("Contrôle"));
        playerPanel.add(mute);
        playerPanel.add(btnStop);
        
        infoPanel.setBorder(BorderFactory.createTitledBorder("Information sur la connexion"));
        infoPanel.add(new JLabel("Nom: " + conn.getName()));
        infoPanel.add(new JLabel("Nom : " +conn.getUser()));
        infoPanel.add(new JLabel("Adresse IP distante : "));
        infoPanel.add(new JLabel(conn.getAdresse().toString()));
        
        infoPanel.add(labelChrono);
        mainTabPanel.add(infoPanel, BorderLayout.NORTH);
        mainTabPanel.add(playerPanel, BorderLayout.CENTER);

        return mainTabPanel;
    }
    
    Runnable runner = new Runnable() {
        @Override
        public void run() {
         try {
            while(running){
             s++;
             if (s == 59){
                 s = 0;
                 m++;
             }
             if (m == 60){
                 m = 0;
                 h++;
             }
             Thread.sleep(1000);
             labelChrono.setText("Temps: "+h+":"+m+":"+s);
             frame.validate();
            }
          } catch (InterruptedException ex) {
               Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
          }
         }   
    };
    Thread chrono = new Thread(runner);
    
    public void startChrono(){
        running = true;
        chrono.start();
    }
    public void stopChrono(){
        running = false;
    }
    
    /**
    *<b>Methode getListeattenteSelection</b>
    * Retourne la valeur séléctioné dans la liste d'attente<br>
    * @return Object 
    */
    public Object getListeattenteSelection(){
        return listattente.getSelectedValue();
    }
    
    /**
    *<b>Methode setUserTextConnected</b>
    * affiche la phrase de bienvenu<br>
    */
    public void setUserTextConnected(){
        if ( control.getCurrentUser() != null ) // si un utilisateur au moins existe
        {
            UserConected.setText("Bonjour, " +control.getCurrentUser().getNom());
            if ( Constant.debug ) System.out.println("change currentuser to " +control.getCurrentUser().getNom());
        }
    }

    //**************************************************************************
    //**************************OBSERVER METHODES*******************************
    //**************************************************************************
        @Override
    public void updateWaitingList(List<Connection> list){
            itemPanel.removeAll();
            for (int i=0; i<list.size(); i++){
                System.out.println("DISPLAY : " + list.get(i).getState());
                buildItem(list.get(i));
            }
            frame.repaint();
            frame.validate();
            frame.pack();
            
    }
        
    @Override
    public void updateActiveList(List<Connection> list){
            tabPane.removeAll();
            for (int i=0; i<list.size(); i++){
                System.out.println("DISPLAY : " + list.get(i).getState());
                buildTab(list.get(i));
            }
            frame.repaint();
            frame.validate();
            frame.pack();
    }
    
    private void modificationFermetureCroix() {
        frame.setDefaultCloseOperation(frame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(
                new WindowAdapter() {

            @Override
                    public void windowClosing(WindowEvent arg0) {
                        quitter();
                        System.exit(0);
                    }
                });
    }
    
    public void quitter() 
    {
        control.stopAutoDiscover();
        control.stopAllActive();
            
            
            Connection c = control.getActiveConnection(control.getFirstActiveID());
            while (c != null) {
                ClientTCP cli = new ClientTCP(c, control);
                cli.arret();
                control.AddConnToWaitList(c);
                control.removeConnToActiveList(c);
                
                c = control.getActiveConnection(control.getFirstActiveID());
            }
            control.disconectAllConnection();
    }
    
    @Override
    public void updateUserList(List<User> list) {}

    @Override
    public void updateCurrentUser(int currentUser) {
        setUserTextConnected();
    }
    
    @Override
    public void updateActivity(boolean activity) {
        ledActivity.removeAll();
        if(activity == true)
            ledActivity.add(new JLabel(iconGreen));
        else if (activity == false)
            ledActivity.add(new JLabel(iconRed));
        
        frame.validate();
    }
    //**************************************************************************
    //**************************FIN OBSERVER METHODES***************************
    //**************************************************************************

    //*************************************************************************
    //****************************LISTENERS************************************
    //*************************************************************************

    /**
    *<b>Class interne MenuListener</b><br>
    * Définit les actions des Items du menu<br>
    */
    private class MenuListener implements ActionListener{
    
    @Override
    public void actionPerformed(ActionEvent e){
        JMenuItem item = (JMenuItem) e.getSource();
        
        if ("btnPref".equals(item.getName())){
            SettingFrame settingWindow = new SettingFrame(control);
            settingWindow.displayFrame();
        }
        else if ("btnCon".equals(item.getName())){
            System.out.println("Bouton nouvelle Connection");
            new NewConnectionFrame(control);
        }
        else if ("btnUser".equals(item.getName())){
            System.out.println("Bouton nouvel utilisateur");
            new ManageUserFrame(control);
        }
        else if ("btnQuit".equals(item.getName())){
            quitter();
            System.exit(0);
        }
        else if ("btnBug".equals(item.getName())){ 
            ClientTCP client = new ClientTCP(null, control);
                
            JOptionPane.showMessageDialog(null, "Il n'y a pas de bug, mais que des fonctionnalités cachées.", "Garantit avec fonctionnalités cachées", JOptionPane.WARNING_MESSAGE);
        }
        else if ("btnReqUDP".equals(item.getName())){
            System.out.println("DEBUG - Capture et envoie UDP");
                try {
                    AudioCapture capture = new AudioCapture("127.0.0.1", 2500, control, control.getLocalSoundSetting().getFormat());
                } catch (SocketException ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                } catch (UnknownHostException ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                }

        }
        else if ("btnSrvUDP".equals(item.getName())){
            System.out.println("DEBUG - Démarrage du Serveur UDP");
            ThreadServerUDP lecteur = new  ThreadServerUDP(control.getLocalSoundSetting().getFormat(), control.getPortUDP());
            lecteur.start();
        }
    }
    }
    
    /**
    *<b>Listener des bouton de la waitlist</b><br> 
    */
    private class WaitPanelListener implements ActionListener{
    
        Connection connection;
        public WaitPanelListener(Connection currentConnexion){
            this.connection = currentConnexion;
        }
        @Override
    public void actionPerformed(ActionEvent e){
        JButton btn = (JButton) e.getSource();
        if("btnAccept".equals(btn.getName())){
                try {
                    control.createAudioSession(this.connection);
                } catch (UnknownHostException ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                } catch (SocketException ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
        }
        else if("btnRefuse".equals(btn.getName()) || "btnAnnul".equals(btn.getName())){
                ClientTCP cli = new ClientTCP(connection, control);
                cli.setRefused(); // rejette la demande
                control.removeConnToWaitList(control.getWaitingConnection(connection.getID()));
        }
    }
    }
    
    /**
    *<b>Listener du bouton nouvelle connexion</b><br> 
    */
    private class ConnectionPanelListener implements ActionListener{
        
        @Override
        public void actionPerformed(ActionEvent e){
        JButton btn = (JButton) e.getSource();
        if ("addbtn".equals(btn.getName())){
             try {
                control.createConnection(textField.getText());
            } catch (UnknownHostException ex) { Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
            else if ("auto".equals(btn.getName())) {
                try {
                    control.discover();
                } catch (IOException ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
    
    /**
    *<b>Listener du bouton nouvelle connexion</b><br> 
    */
    private class tabPanelListener implements ActionListener{
        Connection connection;
        tabPanelListener(Connection connection){
            this.connection = connection;
        }
        
        @Override
        public void actionPerformed(ActionEvent e){
            JButton btn = (JButton) e.getSource();
            if ("stop".equals(btn.getName())){
                connection.stop();
                 ClientTCP cli = new ClientTCP(connection, control);
                cli.arret();
                control.AddConnToWaitList(control.getActiveConnection(connection.getID()));
                control.removeConnToActiveList(control.getActiveConnection(connection.getID()));
            } else if("mute".equals(btn.getName())){
                connection.pause();
            }

        }
    }
    
    /**
    *<b>Listener du bouton nouvelle connexion</b><br> 
    */
    private class KeyListener implements ActionListener{
        int i = 0;
        @Override
        public void actionPerformed(ActionEvent e){
            System.out.println(e.getActionCommand());
            
            System.out.println("go!"+i);
            i++;
        }
    }
}
